#include <QDebug>
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QMap>
#include <QEvent>
#include <QMouseEvent>
#include <QTextCodec>
#include <QFileDialog>
#include <QTimer>
#include <QDateTime>
#include <QScrollBar>
#include <QFile>
#include <QFont>
#include <QElapsedTimer>
#include <QThread>

#include<QUrl>
#include<QDesktopServices>
#include "MessageBox.h"
#include "MainWindow.h"
#include "ui_mainwindow.h"
#include "statusLED.h"
#include "serialCommand.h"


bool FLAG_DORM_STATUS =1;  //通信机当前状态标志位
bool FLAG_IDLE_STATUS =0;
bool FLAG_ACQU_STATUS =0;
int CommEnter=-1;//用来判断用户按下了哪种命令，默认-1关闭接收显示
QByteArray g_rxArr;//全局变量，保存串口读取的数据，主要为了拼数据包
void processRxData(const QByteArray& data, QByteArray& outData);//用来处理串口数据，保证数据包完整，以\n结尾为一个完整数据包

MainWindow::MainWindow(QWidget* parent) :
    QMainWindow(parent), is_open_serailport(false),
    serial_port(new QSerialPort(this)), ui(new Ui::MainWindow)
{
    this->last_combox_index = 0;
    this->rcv_data_map = new QMap<quint64, QMap<SEND_TYPE, QByteArray>>();
    ui->setupUi(this);
    ui->menuHelp->setMouseTracking(true);

    initSerialPortList();
    initBautrateList();
    initDataBitList();
    initStopBitList();
    initCheckBitList();

    initLaunModList();//初始化发射模式列表
    initSINV_List();
    initLaunFrameType();
    initFrameHeadList();
    initLaunFreqRange();
    UiTextInit();

    QObject::connect(this->ui->pB_clearLog, &QPushButton::clicked, [this]
    {
        this->rcv_data_map->clear();
    });
    QObject::connect(this->ui->actionAbout, &QAction::triggered, [this]
    {
        MessageBox::about(this, "关于", "本软件由海滨开发且开放源代码，遵循LGPL协议。");
    });

    QObject::connect(this->ui->actionEmail, &QAction::triggered, [this]
    {   //插入一个邮箱地址，并且使其成为一个可点击的超链接
        QString email = "chengzhi_li@tju.edu.cn";
        QString emailLink = "<a href=\"mailto:" + email + "\">" + email + "</a>";
        MessageBox::contact(this, "邮箱", emailLink);
    });
    QObject::connect(this->ui->actionAbout_QT, &QAction::triggered, &qApp->aboutQt);

    QObject::connect(this->ui->pB_saveRevData, SIGNAL(clicked()), this, SLOT(slotOnSaveData()));
    QObject::connect(this->ui->pB_saveSendData, SIGNAL(clicked()), this, SLOT(slotOnSaveData()));
    QObject::connect(this->ui->pB_saveAllData, SIGNAL(clicked()), this, SLOT(slotOnSaveData()));

    QObject::connect(this->ui->rB_rcvMode_text, &QRadioButton::toggled, [this](bool is_checked)
    {
        if(this->rcv_data_map->size() > 0)
        {
            this->ui->tE_rcvcon->clear();
            foreach(qint64 unix_timestamp, this->rcv_data_map->keys())
            {
                QString rcvStr;

                const QMap<SEND_TYPE, QByteArray>& map_data = this->rcv_data_map->value(unix_timestamp);
                const SEND_TYPE& type = map_data.firstKey();
                const QByteArray& rcv_data = map_data.value(type);
                if(type == Serial_RCV)
                {
                    rcvStr += "[RX] ";
                }
                else
                {
                    rcvStr += "[TX] ";
                }
                rcvStr += QDateTime::fromMSecsSinceEpoch(unix_timestamp).toString("yyyy-MM-dd hh:mm:ss zzz");
                rcvStr += "\r\n";
                if(is_checked)
                {
                    rcvStr += this->GetCorrectUnicode(rcv_data);
                }
                else
                {
                    foreach(quint8 data, rcv_data)
                    {
                        if(data < 16)
                        {
                            rcvStr += "0" + QString::number(data, 16) + " ";
                        }
                        else
                        {
                            rcvStr += QString::number(data, 16) + " ";
                        }
                    }
                }
                this->ui->tE_rcvcon->append(rcvStr);

            }
        }
    });
    QObject::connect(this->serial_port, &QSerialPort::readyRead, [this]
    {
        if(CommEnter==OPEN_RX_SHOW){//说明进入了采集
            if(!this->is_open_serailport) return;
            QByteArray rx_arr=this->serial_port->readAll();
            QByteArray rcv_data;
            processRxData(rx_arr,rcv_data);//保证rcv_data是完整的数据包，\n结尾

            if(rcv_data.length() <= 0) return;//说明不是完整的数据包
            g_rxArr.clear();//走到这说明收到完整数据包，需要清除缓存在全局变量的数据

            quint64 unix_timestamp = QDateTime::currentMSecsSinceEpoch();   //获取当前时间
            QMap <SEND_TYPE, QByteArray> insert_data;
            insert_data.insert(Serial_RCV, rcv_data);
            this->rcv_data_map->insert(unix_timestamp, insert_data);
            QString rcvStr("[RX] ");
            rcvStr += QDateTime::fromMSecsSinceEpoch(unix_timestamp).toString("yyyy-MM-dd hh:mm:ss zzz");
            rcvStr += "\r\n";

            if(this->ui->rB_rcvMode_text->isChecked())
            {
                rcvStr += this->GetCorrectUnicode(rcv_data);
            }
            else if(this->ui->rB_rcvMode_hex->isChecked())
            {
                foreach(quint8 data, rcv_data)
                {
                    if(data < 16)
                    {
                        rcvStr += "0" + QString::number(data, 16) + " ";
                    }
                    else
                    {
                        rcvStr += QString::number(data, 16) + " ";
                    }
                }
            }

            this->ui->tE_rcvcon->setTextColor(Qt::darkGray);
            this->ui->tE_rcvcon->append(rcvStr);

            this->rcv_cnt += rcv_data.length();
            this->ui->lE_rcv_cnt->setText(QString::number(this->rcv_cnt));

            QScrollBar* scrollBar = this->ui->tE_rcvcon->verticalScrollBar();
            scrollBar->setValue(scrollBar->maximum());
        }//end of if(CommEnter==OPEN_RX_SHOW)
/*******************************************************************************************************************************
 *                                              2023-10-1 licz编写
*******************************************************************************************************************************/
        else if(CommEnter==CLOSE_RX_SHOW)
        {
            QByteArray rx_buf=this->serial_port->readAll();
            QByteArray rcv_data;
            processRxData(rx_buf,rcv_data);//等待完整的数据包
            if(rcv_data.length() <= 0) return;//说明不是完整的数据包
            g_rxArr.clear();//走到这说明收到完整数据包，需要清除缓存在全局变量的数据
            QString rx_str=QString::fromUtf8(rcv_data);
            qDebug()<<" CLOSE_RX_SHOW "<<"recv msg :"<<rx_str;
        }
        else //按下了状态切换按钮
        {
            QByteArray rx_buf=this->serial_port->readAll();
            QByteArray rcv_data;
            processRxData(rx_buf,rcv_data);//等待完整的数据包
            if(rcv_data.length() <= 0) return;//说明不是完整的数据包
            g_rxArr.clear();//走到这说明收到完整数据包，需要清除缓存在全局变量的数据
            QString rx_str=QString::fromUtf8(rcv_data);
            qDebug()<<"recv msg :"<<rx_str;
            SwitchStatusLED(rx_str);
        }
    });

    QObject::connect(ui->pB_openSerail, &QPushButton::clicked, [this]
    {
        if(this->is_open_serailport)
        {
            if(serial_port->isOpen())
            {
                serial_port->close();
            }
            if(this->ui->pB_openSerail->text() == "关闭")
            {
                this->ui->pB_openSerail->setText("打开");
            }
            if(!this->ui->cB_serailport->isEnabled())
            {
                this->ui->cB_serailport->setEnabled(true);
            }

            this->is_open_serailport = false;
        }
        else
        {
            QString portname = this->ui->cB_serailport->currentText();
            if(portname.isEmpty())
            {
                return;
            }
            if(serial_port->isOpen())
            {
                serial_port->close();
            }
            bool ret = true;
            // 获取串口号
            serial_port->setPortName(portname);
            // 获取波特率
            ret &= serial_port->setBaudRate(this->ui->cB_bautrate->currentData().toInt());
            if(!ret)
            {

                qDebug() << "设置波特率失败，失败原因：" << serial_port->errorString();
                MessageBox::warning(this, "设置波特率失败", QString("原因:") + serial_port->errorString());
                return;
            }
            // 获取数据位
            QSerialPort::DataBits databits = static_cast<QSerialPort::DataBits>(this->ui->cB_databits->currentData().toInt());
            ret &= serial_port->setDataBits(databits);
            if(!ret)
            {

                qDebug() << "设置数据位失败，失败原因：" << serial_port->errorString();
                MessageBox::warning(this, "设置数据位失败", QString("原因:") + serial_port->errorString());
                return;
            }
            // 获取停止位
            QSerialPort::StopBits stopbits = static_cast<QSerialPort::StopBits>(this->ui->cB_stopbit->currentData().toInt());
            ret &= serial_port->setStopBits(stopbits);
            if(!ret)
            {

                qDebug() << "设置停止位失败，失败原因：" << serial_port->errorString();
                MessageBox::warning(this, "错误", QString("设置停止位失败，失败原因：") + serial_port->errorString());
                return;
            }
            // 获取校验位
            QSerialPort::Parity checkbits = static_cast<QSerialPort::Parity>(this->ui->cB_checkbit->currentData().toInt());
            ret &= serial_port->setParity(checkbits);
            if(!ret)
            {

                qDebug() << "设置校验位失败，失败原因：" << serial_port->errorString();
                MessageBox::warning(this, "设置校验位失败", QString("原因:") + serial_port->errorString());
                return;
            }
            // 设置流控
            ret &= serial_port->setFlowControl(QSerialPort::NoFlowControl);
            if(!ret)
            {

                qDebug() << "设置流控失败，失败原因：" << serial_port->errorString();
                MessageBox::warning(this, "设置流控失败", QString("原因:") + serial_port->errorString());
                return;
            }
            // 设置读写
            ret &= serial_port->open(QSerialPort::ReadWrite);
            if(ret)
            {
                this->ui->pB_openSerail->setText("关闭");
                if(this->ui->cB_serailport->isEnabled())
                {
                    this->ui->cB_serailport->setEnabled(false);
                }
                this->is_open_serailport = true;


            }
            else
            {
                qDebug() << "自定义MessageBox提示打开错误" << serial_port->errorString();
                MessageBox::warning(this, "打开串口失败", QString("原因:") + serial_port->errorString());
            }
        }
    });



    this->send_timer = new QTimer(this);
    QObject::connect(this->send_timer, SIGNAL(timeout()), this, SLOT(slotOnSendSerialContent()));
    QObject::connect(ui->pB_senddata, SIGNAL(clicked()), this, SLOT(slotOnSendSerialContent()));
    QObject::connect(ui->pB_autoSend, &QPushButton::clicked, [this]
    {

        if(this->ui->pB_autoSend->text() == "自动发送")
        {
            bool is_ok = false;
            int send_inter_ms = this->ui->lE_send_ms->text()
            .toInt(&is_ok);
            is_ok &= !this->ui->tE_sendcon->toPlainText().isEmpty();
            is_ok &= this->is_open_serailport;
            if(is_ok&&FLAG_IDLE_STATUS)
            {
                slotOnSendSerialContent();//定时器并不会立刻触发发送数据，而是要经过设定的时间间隔后才发送数据。这可能会导致用户点击 "自动发送" 按钮后需要等待设定的时间间隔才会发送数据，而不是立即发送。
                this->send_timer->start(send_inter_ms*1000);//设置为秒
                this->ui->pB_autoSend->setText("停止发送");
                this->ui->pB_senddata->setDisabled(true);
                this->ui->pB_sendfile->setDisabled(true);
            }
            else if (!FLAG_IDLE_STATUS)
            {
                qDebug() << "报错";
                MessageBox::warning(this, "错误", "请先进入空闲再发送 ！");
            }
            else
            {
                qDebug() << "报错";
                MessageBox::warning(this, "错误", "请查看串口是否打开以及时间间隔和内容是否设置！");
            }

        }
        else
        {
            this->ui->pB_senddata->setDisabled(false);
            this->ui->pB_sendfile->setDisabled(false);
            this->ui->pB_autoSend->setText("自动发送");
            this->send_timer->stop();
        }
    });

    QObject::connect(this->ui->pB_clear_count, &QPushButton::clicked, [this]()
    {
        this->send_cnt = 0;
        this->ui->lE_send_cnt->setText(QString::number(this->send_cnt));
        this->rcv_cnt = 0;
        this->ui->lE_rcv_cnt->setText(QString::number(this->rcv_cnt));
    });
    this->ui->pB_clear_count->click();
    QObject::connect(this->ui->pB_sendfile, &QPushButton::clicked, [this]
    {
        //发送文件功能不可用
        //this->ui->pB_sendfile->setDisabled(true);
        return;

        if(!this->is_open_serailport) return;
        QString fileName = QFileDialog::getOpenFileName(this, "打开文件");
        if(!fileName.isEmpty())
        {
            QFile file(fileName);
            if(!file.open(QIODevice::ReadOnly))
            {
                qDebug() << "open fail!";
                return;
            }
            const QByteArray& send_buffer = file.readAll();
            if(send_buffer.length() > 0)
            {
                QMap<SEND_TYPE, QByteArray> insert_data;
                const quint64& unix_timestamp = QDateTime::currentMSecsSinceEpoch();   //获取当前时间
                insert_data.insert(Serial_SEND, send_buffer);

                QString sendStr("[发] ");
                sendStr += QDateTime::fromMSecsSinceEpoch(unix_timestamp).toString("yyyy-MM-dd hh:mm:ss zzz");
                sendStr += "\r\n";

                if(this->ui->rB_rcvMode_text->isChecked())
                {
                    if(this->ui->rB_sendMode_hex->isChecked())
                    {
                        sendStr += send_buffer;
                    }
                    else
                    {
                        sendStr += QString(send_buffer);
                    }

                }
                else if(this->ui->rB_rcvMode_hex->isChecked())
                {
                    foreach(quint8 data, send_buffer)
                    {
                        if(data < 16)
                        {
                            sendStr += "0" + QString::number(data, 16) + " ";
                        }
                        else
                        {
                            sendStr += QString::number(data, 16) + " ";
                        }
                    }
                }
                this->ui->tE_rcvcon->append(sendStr);
                this->rcv_data_map->insert(unix_timestamp, insert_data);
                this->serial_port->write(send_buffer);

                this->send_cnt += send_buffer.length();
                this->ui->lE_send_cnt->setText(QString::number(this->send_cnt));

                QScrollBar* scrollBar = this->ui->tE_rcvcon->verticalScrollBar();
                scrollBar->setValue(scrollBar->maximum());
                MessageBox::info(this, "成功", "发送文件成功");
            }

            file.close();

        }
    });
}

MainWindow::~MainWindow()
{
    if(is_open_serailport)
    {
        serial_port->close();
    }
    delete serial_port;
    delete ui;
    delete rcv_data_map;
}



QString MainWindow::GetCorrectUnicode(const QByteArray& ba)
{
    QTextCodec::ConverterState state;
    QTextCodec* codec = QTextCodec::codecForName("UTF-8");
    QString text = codec->toUnicode(ba.constData(), ba.size(), &state);
    if(state.invalidChars > 0)
    {
        text = QTextCodec::codecForName("GBK")->toUnicode(ba);
    }
    else
    {
        text = ba;
    }
    return text;
}

void MainWindow::initSerialPortList()
{
    QList<QSerialPortInfo> infolist = QSerialPortInfo::availablePorts();
    foreach(const QSerialPortInfo& info, infolist)
    {
        ui->cB_serailport->addItem(info.portName());
    }
}

void MainWindow::initBautrateList()
{
    QStringList bautrate_list;
    bautrate_list << "600" << "1200" << "2400" << "4800" << "9600" << "14400"
                  << "19200" << "28800" << "38400" << "57600" << "115200"
                  << "230400" << "460800";
    foreach(const QString& bautrate_str, bautrate_list)
    {
        ui->cB_bautrate->addItem(bautrate_str, bautrate_str.toInt());
    }
    ui->cB_bautrate->setCurrentText("115200");
    ui->cB_bautrate->installEventFilter(this);
    QObject::connect(ui->cB_bautrate, &QComboBox::currentTextChanged, [this](QString)
    {
        if(this->is_open_serailport)
        {
            bool ret = this->serial_port->setBaudRate(this->ui->cB_bautrate->currentData().toInt());
            if(!ret)
            {
                qDebug() << "切换失败";
                this->ui->cB_bautrate->setCurrentIndex(this->last_combox_index);
                MessageBox::warning(this, "错误", "切换失败，可能当前硬件不支持这种波特率！");
            }
        }
    });
}

void MainWindow::initDataBitList()
{
    QMap<QString, QSerialPort::DataBits> databits_list;
    databits_list.insert("8", QSerialPort::Data8);
    databits_list.insert("7", QSerialPort::Data7);
    databits_list.insert("6", QSerialPort::Data6);
    databits_list.insert("5", QSerialPort::Data5);
    foreach(const QString& key, databits_list.keys())
    {
        ui->cB_databits->addItem(key, databits_list[key]);
    }
    if(ui->cB_databits->count() == databits_list.count())
    {
        ui->cB_databits->setCurrentIndex(ui->cB_databits->count() - 1);
    }
    ui->cB_databits->installEventFilter(this);
    QObject::connect(ui->cB_databits, &QComboBox::currentTextChanged, [this](QString)
    {
        if(this->is_open_serailport)
        {
            QSerialPort::DataBits databits = static_cast<QSerialPort::DataBits>(this->ui->cB_databits->currentData().toInt());
            bool ret = this->serial_port->setDataBits(databits);
            if(!ret)
            {
                qDebug() << "切换失败";
                this->ui->cB_databits->setCurrentIndex(this->last_combox_index);
                MessageBox::warning(this, "错误", "切换失败，可能当前硬件不支持这种数据位！");
//                return false;
            }
        }
    });
}

//初始化发射模式列表
void MainWindow::initLaunModList()
{
    QStringList LaunMod_list;
    LaunMod_list << "32FSK" << "8M16FSK" << "OFDM";
    foreach(const QString& LaunMod_str,LaunMod_list)
    {
        ui->cB_LaunMod->addItem(LaunMod_str, LaunMod_str.toInt());
    }
    ui->cB_LaunMod->setCurrentText("32FSK");//初始默认32FSK
   // ui->cB_LaunMod->installEventFilter(this);
}

void MainWindow::initSINV_List(void)
{
    QStringList SINV_list;
    SINV_list << "M0" << "M1" << "M2"<< "M3";
    foreach(const QString& SINV_str,SINV_list)
    {
        ui->cB_SINV->addItem(SINV_str, SINV_str.toInt());
    }
    ui->cB_SINV->setCurrentText("M0");//初始默认32FSK
    //ui->cB_SINV->installEventFilter(this);
}
void MainWindow::initFrameHeadList(void)
{
    QStringList FrameHead_list;
    FrameHead_list << "LFM" << "HFM" << "PNH";
    foreach(const QString& FrameHead_str,FrameHead_list)
    {

        ui->cB_FrameHead->addItem(FrameHead_str, FrameHead_str.toInt());
    }
    ui->cB_FrameHead->setCurrentText("LFM");
    //ui->cB_FramHead->installEventFilter(this);
}
void MainWindow::initLaunFreqRange()
{
    QStringList LaunFreqRange_list;
    LaunFreqRange_list << "11-17kHz" << "21-27kHz" << "20-30kHz";
    foreach(const QString& LaunFreqRange_str,LaunFreqRange_list)
    {

        ui->cB_LaunFreqRange->addItem(LaunFreqRange_str, LaunFreqRange_str.toInt());
    }
    ui->cB_LaunFreqRange->setCurrentText("20-30kHz");
    //ui->cB_FramHead->installEventFilter(this);
}

void MainWindow::initLaunFrameType()
{
    QStringList LaunFrameType_list;
    LaunFrameType_list << "Broadcast" << "P2P";
    foreach(const QString& LaunFrameType_str,LaunFrameType_list)
    {

        ui->cB_LaunFrameType->addItem(LaunFrameType_str, LaunFrameType_str.toInt());
    }
    ui->cB_LaunFrameType->setCurrentText("Broadcast");
}
void MainWindow::initStopBitList()
{

    QMap<QString, QSerialPort::StopBits> stopbit_list;
    stopbit_list.insert("1", QSerialPort::OneStop);
    stopbit_list.insert("1.5", QSerialPort::OneAndHalfStop);
    stopbit_list.insert("2", QSerialPort::TwoStop);
    foreach(const QString& stopbit_key, stopbit_list.keys())
    {
        ui->cB_stopbit->addItem(stopbit_key, stopbit_list[stopbit_key]);
    }
    ui->cB_stopbit->installEventFilter(this);
    QObject::connect(ui->cB_stopbit, &QComboBox::currentTextChanged, [this](QString)
    {
        if(this->is_open_serailport)
        {
            QSerialPort::StopBits stopbits = static_cast<QSerialPort::StopBits>(this->ui->cB_stopbit->currentData().toInt());
            bool ret = this->serial_port->setStopBits(stopbits);
            if(!ret)
            {
                qDebug() << "切换失败";
                MessageBox::warning(this, "错误", "切换失败，可能当前硬件不支持这种停止位！");
                this->ui->cB_stopbit->setCurrentIndex(this->last_combox_index);
//                this->ui->cB_stopbit->
//                return false;
            }
        }
    });
}

void MainWindow::initCheckBitList()
{
    QMap<QString, QSerialPort::Parity> checkbit_list;
    checkbit_list.insert("无校验", QSerialPort::NoParity);
    checkbit_list.insert("奇校验", QSerialPort::OddParity);
    checkbit_list.insert("偶校验", QSerialPort::EvenParity);
    checkbit_list.insert("1 校验", QSerialPort::MarkParity);
    checkbit_list.insert("0 校验", QSerialPort::SpaceParity);
    foreach(const QString& key, checkbit_list.keys())
    {
        ui->cB_checkbit->addItem(key, checkbit_list[key]);
    }
    ui->cB_checkbit->setCurrentText("无校验");
    ui->cB_checkbit->installEventFilter(this);
    QObject::connect(ui->cB_checkbit, &QComboBox::currentTextChanged, [this](QString)
    {
        if(this->is_open_serailport)
        {
            QSerialPort::Parity checkbits = static_cast<QSerialPort::Parity>(this->ui->cB_checkbit->currentData().toInt());
            bool ret = this->serial_port->setParity(checkbits);
            if(!ret)
            {
                qDebug() << "切换失败";
                MessageBox::warning(this, "错误", "切换失败，可能当前硬件不支持这种校验位！");
                this->ui->cB_checkbit->setCurrentIndex(this->last_combox_index);
//                return false;
            }
        }
    });
}
//该事件过滤器方法的作用是允许程序对指定的下拉框控件的鼠标左键点击事件进行处理，例如保存当前下拉框的索引等操作。
bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
    bool ret = (watched == ui->cB_bautrate);
    ret |= (watched == ui->cB_checkbit);
    ret |= (watched == ui->cB_databits);
    ret |= (watched == ui->cB_stopbit);
    if(ret)
    {
        if(event->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
            if(mouse_event->button() == Qt::LeftButton)
            {
                this->last_combox_index = static_cast<QComboBox*>(watched)->currentIndex();
            }
        }
    }


    return QMainWindow::eventFilter(watched, event);
}

void MainWindow::slotOnSendSerialContent()
{

    if(this->is_open_serailport)
    {
        if(!FLAG_IDLE_STATUS)//只有进入IDLE才可发射
        {
            MessageBox::warning(this, "错误", "请先进入空闲再发送 ！");
            return;
        }
        if(FLAG_IDLE_STATUS)//只有进入IDLE才可发射
        {
            //获取发射方式ASCCI还是HEX
             QString sendMod;
             if(this->ui->rB_sendMode_text->isChecked()){
                 sendMod="A,";
             }else if(this->ui->rB_sendMode_hex->isChecked()){
                 sendMod="H,";
             }
            //获取源地址和目的地址
            QString SrcAddStr= this->ui->LE_SrcAddr->text();
            SrcAddStr.remove(QRegularExpression("\\s+"));
            QString DestAddStr= this->ui->LE_DestAddr->text();
            DestAddStr.remove(QRegularExpression("\\s+"));
            if(SrcAddStr.length()<1||DestAddStr.length()<1)
            {
                MessageBox::warning(this, "错误", "地址不能为空！");
                return;
            }
            if(SrcAddStr.toInt()>31||DestAddStr.toInt()>31)
            {
                MessageBox::warning(this, "错误", "当前设备地址取值范围 0~31 ！");
                return;
            }
            SrcAddStr+=",";
            DestAddStr+=",";
            QString currentLaunMod = this->ui->cB_LaunMod->currentText();//获取当前发射方式

            QString contentString;//存放文本编辑器(QTextEdit)中的纯文本内容，也就是需要发射的数据
            QString LaunHeadCommStr;//存放发射的头命令，
            if(currentLaunMod=="32FSK")
            {
                 //格式"$ACZF,A,1,15,FSK32,SINV0,";
                 LaunHeadCommStr="$ACZF,";
                 LaunHeadCommStr+=sendMod;
                 LaunHeadCommStr+=SrcAddStr;
                 LaunHeadCommStr+=DestAddStr;
                 LaunHeadCommStr+="FSK32,SINV0,";
            }
            else if(currentLaunMod=="8M16FSK")
            {
                  //格式"$ACZF,A,1,15,FSK8M16,SINV0,";
                  LaunHeadCommStr="$ACZF,";
                  LaunHeadCommStr+=sendMod;
                  LaunHeadCommStr+=SrcAddStr;
                  LaunHeadCommStr+=DestAddStr;
                  LaunHeadCommStr+="FSK8M16,SINV0,";
            }
            else if(currentLaunMod=="OFDM")
            {
                MessageBox::warning(this, "错误", "当前设备不支持OFDM ！");
                return;
                // LaunHeadCommStr="";//截止到2023-10-2还没移植好
            }
            QString LaunFrameType = this->ui->cB_LaunFrameType->currentText();//广播还是p2p
            if(LaunFrameType=="Broadcast"){
                LaunHeadCommStr+="0,";
            }
            else {
                LaunHeadCommStr+="1,";
            }
            contentString = this->ui->tE_sendcon->toPlainText();//是获取名为 tE_sendcon 的 QTextEdit 组件中的纯文本内容。
            qDebug()<<"当前选择的发射参数为："<<LaunHeadCommStr;
            if(!contentString.isEmpty())
            {
                QByteArray send_arr;

                if(this->ui->rB_sendMode_text->isChecked())
                {
                    QTextCodec* gbk = QTextCodec::codecForName("gbk");
                    send_arr = gbk->fromUnicode(contentString.toLocal8Bit().data());
                    qDebug()<<"变成ASCII："<<send_arr;
                }
                else if(this->ui->rB_sendMode_hex->isChecked())
                {
                    contentString.remove(QRegularExpression("\\s+"));//结合正则表达式来移除字符串中的所有空格
                    int content_length = contentString.length();
                    for (int i = 0; i < content_length; ++i) {
                        QChar ch = contentString.at(i);
                        if (!(ch.isDigit() || (ch.toLower().unicode() >= 'a' && ch.toLower().unicode() <= 'f'))) {
                            qDebug() << "请输入只包含从0到F范围内的字符！";
                            MessageBox::warning(this, "错误", "请输入只包含从0到F范围内的字符！");
                            return;
                        }
                    }
                    char hexchar, hexchar_next;
                    for(int i = 0; i < content_length; i++)
                    {
                        hexchar = contentString[i].toLower().toLatin1();
    //                    qDebug("Test:%#x", hexchar);
                        switch(hexchar)
                        {
                            case '\r':
                            case '\n':
                            case ' ':
                                break;
                            default:
                                if(hexchar >= '0' && hexchar <= '9')
                                {
                                    if(i + 1 < content_length)
                                    {
                                        hexchar_next = contentString[i + 1].toLower().toLatin1();
                                        if(hexchar_next >= '0' && hexchar_next <= '9')
                                        {
                                            send_arr.append((char)(((hexchar - 0x30) << 4) | (hexchar_next - 0x30)));
                                            i++;
                                        }
                                        else if(hexchar_next >= 'a' && hexchar_next <= 'f')
                                        {
                                            send_arr.append((char)(((hexchar - 0x30) << 4) | (hexchar_next - 'a' + 10)));
                                            i++;
                                        }
                                        else if(hexchar_next == '\n' || hexchar_next == '\r' || hexchar_next == ' ')
                                        {
                                            send_arr.append((char)(hexchar - 0x30));
                                            i++;
                                        }
                                        else
                                        {
                                            send_arr.append((char)(hexchar - 0x30));
                                            i = content_length;
                                        }
                                    }
                                    else
                                    {
                                        send_arr.append((char)(hexchar - 0x30));
                                    }
                                }
                                else if(hexchar >= 'a' && hexchar <= 'f')
                                {
                                    if(i + 1 < content_length)
                                    {
                                        hexchar_next = contentString[i + 1].toLower().toLatin1();
                                        if(hexchar_next >= '0' && hexchar_next <= '9')
                                        {
                                            send_arr.append((char)(((hexchar - 'a' + 10) << 4) | (hexchar_next - 0x30)));
                                            i++;
                                        }
                                        else if(hexchar_next >= 'a' && hexchar_next <= 'f')
                                        {
                                            send_arr.append((char)(((hexchar - 'a' + 10) << 4) | (hexchar_next - 'a' + 10)));
                                            i++;
                                        }
                                        else if(hexchar_next == '\n' || hexchar_next == '\r' || hexchar_next == ' ')
                                        {
                                            send_arr.append((char)(hexchar - 'a' + 10));
                                            i++;
                                        }
                                        else
                                        {
                                            send_arr.append((char)(hexchar - 'a' + 10));
                                            i = content_length;
                                        }
                                    }
                                    else
                                    {
                                        send_arr.append((char)(hexchar - 'a' + 10));
                                    }
                                }
                                else
                                {
                                    i = content_length;
                                }
                                break;
                        }
                    }
                   qDebug()<<"变成HEX:"<<send_arr; //end for
                }
                //end else if(this->ui->rB_sendMode_hex->isChecked())
                if(send_arr.length() > 0)
                {
                    QMap<SEND_TYPE, QByteArray> insert_data;
                    const quint64& unix_timestamp = QDateTime::currentMSecsSinceEpoch();   //获取当前时间
                    insert_data.insert(Serial_SEND, send_arr);

                    QString sendStr("[TX] ");
                    sendStr += QDateTime::fromMSecsSinceEpoch(unix_timestamp).toString("yyyy-MM-dd hh:mm:ss zzz");
                    sendStr += "\r\n";

                    if(this->ui->rB_rcvMode_text->isChecked())
                    {
                        if(this->ui->rB_sendMode_hex->isChecked())
                        {
                            sendStr += send_arr;
                        }
                        else
                        {
                            sendStr += contentString;
                        }

                    }
                    else if(this->ui->rB_rcvMode_hex->isChecked())
                    {
                        foreach(quint8 data, send_arr)
                        {
                            if(data < 16)
                            {
                                sendStr += "0" + QString::number(data, 16) + " ";
                            }
                            else
                            {
                                sendStr += QString::number(data, 16) + " ";
                            }
                        }
                    }
                    //发送的数据字体颜色为红
                    this->ui->tE_rcvcon->setTextColor(Qt::red);
                    this->ui->tE_rcvcon->append(sendStr);
                    this->rcv_data_map->insert(unix_timestamp, insert_data);

                    QTextCodec* gbk = QTextCodec::codecForName("gbk");
                    QByteArray real_tx_arr = gbk->fromUnicode(LaunHeadCommStr.toLocal8Bit().data());//添加头
                    real_tx_arr+=send_arr;//追加要发的数据，也就是是获取名为 tE_sendcon 的 QTextEdit 组件中的纯文本内容。
                    real_tx_arr+=gbk->fromUnicode(command_tail.toLocal8Bit().data());//添加尾
                    qDebug()<<"Real Send :"<<real_tx_arr;
                    this->serial_port->write(real_tx_arr);//真正从串口发的数据
                    this->send_cnt += send_arr.length();//只计算要发的数据位长度，不包括命令头和命令尾的长度
                    this->ui->lE_send_cnt->setText(QString::number(this->send_cnt));

                    QScrollBar* scrollBar = this->ui->tE_rcvcon->verticalScrollBar();
                    scrollBar->setValue(scrollBar->maximum());
                }
            }
            //end !contentString.isEmpty()
        }//end if(FLAG_IDLE_STATUS)//只有进入IDLE才可发射

    } // end this->is_open_serial
    if(!this->is_open_serailport)
    {
        MessageBox::warning(this, "错误", "请打开串口 ！");
        return;
    }



}

void MainWindow::slotOnSaveData()
{

    QString fileName = QFileDialog::getSaveFileName(this, "保存文件");
    if(!fileName.isEmpty())
    {
        QFile file(fileName);
        if(!file.open(QIODevice::WriteOnly))
        {
            qDebug() << "open fail!";
            return;
        }
        QDataStream w_stream(&file);
        QByteArray w_data;
        QMap<quint64, QMap<SEND_TYPE, QByteArray>>::Iterator iter = this->rcv_data_map->begin();
        QObject* sender = this->sender();
        while(iter != this->rcv_data_map->end())
        {
            SEND_TYPE type = iter.value().firstKey();

            if(sender == this->ui->pB_saveRevData)
            {
                if(type == Serial_RCV)
                {
                    w_data.append(iter.value().value(type));
                }
            }
            else if(sender == this->ui->pB_saveSendData)
            {
                if(type == Serial_SEND)
                {
                    w_data.append(iter.value().value(type));
                }

            }
            else if(sender == this->ui->pB_saveAllData)
            {
                w_data.append(iter.value().value(type));
            }

            iter++;
        }
        w_stream.writeRawData(w_data.data(), w_data.length());
        file.close();
        MessageBox::info(this, "成功", "保存文件成功");
    }
}


void MainWindow::UiTextInit()
{
    //设置状态灯初始为灰色
    initLED();
    setLED(this->ui->labDORM, 'g', LED_SIZE);
    this->ui->texIDLE->setAlignment(Qt::AlignTop);
    this->ui->texACQU->setAlignment(Qt::AlignTop);
    this->ui->texDORM->setAlignment(Qt::AlignTop);

    this->ui->labLaunMod->setAlignment(Qt::AlignCenter); // 将文本水平居中显示
    this->ui->LE_LaunVol->setText("100");//发射音量初始默认值100
}

void MainWindow::initLED()
{
    setLED(this->ui->labIDLE, 'b', LED_SIZE);//灰色
    setLED(this->ui->labDORM, 'b', LED_SIZE);//灰色
    setLED(this->ui->labACQU, 'b', LED_SIZE);//灰色
}

void MainWindow::setFLAG(QString flag)
{
    if(flag=="FLAG_DORM")
    {
        FLAG_DORM_STATUS =1;  //通信机当前状态标志位
        FLAG_IDLE_STATUS =0;
        FLAG_ACQU_STATUS =0;
        qDebug()<<"FLAG_DORM";
    }
    else if(flag=="FLAG_IDLE")
    {
        FLAG_DORM_STATUS =0;  //通信机当前状态标志位
        FLAG_IDLE_STATUS =1;
        FLAG_ACQU_STATUS =0;
        qDebug()<<"FLAG_IDLE";
    }
    else if(flag=="FLAG_ACQU")
    {
        FLAG_DORM_STATUS =0;  //通信机当前状态标志位
        FLAG_IDLE_STATUS =0;
        FLAG_ACQU_STATUS =1;
        qDebug()<<"FLAG_ACQU";
    }
}

void MainWindow::SwitchStatusLED(QString &rx_str)
{
    // 从结果列表中获取电压、电流和时间戳字段的值
    QString BatV,BatC,dateTime,sdCardGB;
    bool rxSysInfo;//收到了BatV RTC
    switch (CommEnter)
    {
        case ENTER_DORM:
            if(rx_str.contains("DORM"))
            {   //成功切换到睡眠，设置DORM状态灯为绿色
                setLED(this->ui->labDORM, 'g', LED_SIZE);//灰色
                qDebug()<<"receive DORM :"<<rx_str;
                setFLAG("FLAG_DORM");
                CommEnter=CLOSE_RX_SHOW;
            }
            else
            {
                CommEnter=ENTER_DORM;
            }
        break;
        case ENTER_IDLE:
            rxSysInfo=getBatVTimestampFromMessage(rx_str,BatV,BatC,dateTime,sdCardGB);
            if(rxSysInfo)//用来显示电压、电流、RTC
            {
                qDebug()<<"BatV :"<<BatV<<"BatC :"<<BatC<<"RTC :"<<dateTime<<"SdCardGB:"<<sdCardGB;
                this->ui->LE_BatV->setText(BatV);
                this->ui->LE_BatC->setText(BatC);
                if(FLAG_DORM_STATUS)
                {
                     this->ui->LE_SysRTC->setText(dateTime);
                }
                this->ui->LE_SDcard->setText(sdCardGB);
            }
            if(rx_str.contains("IDLE"))
            {
                setLED(this->ui->labIDLE, 'g', LED_SIZE);//绿色
                qDebug()<<"receive IDLE :"<<rx_str;
                setFLAG("FLAG_IDLE");
                CommEnter=CLOSE_RX_SHOW;
             }
            else
            {
                CommEnter=ENTER_IDLE;
            }
        break;
        case ENTER_ACQU:
            if(rx_str.contains("AZCT,P,ACQU"))
            {
                setLED(this->ui->labACQU, 'g', LED_SIZE);//绿色
                qDebug()<<"receive ACQU :"<<rx_str;
                setFLAG("FLAG_ACQU");
                CommEnter=OPEN_RX_SHOW;
            }
            else
            {
                CommEnter=ENTER_ACQU;
            }
        break;
        case ENTER_STATE:
            //initLED();//清空状态灯
            rxSysInfo=getBatVTimestampFromMessage(rx_str,BatV,BatC,dateTime,sdCardGB);
            if(rxSysInfo)//用来显示电压、电流、RTC
            {
                 qDebug()<<"BatV :"<<BatV<<"BatC :"<<BatC<<"RTC :"<<dateTime<<"SdCardGB:"<<sdCardGB;
                this->ui->LE_BatV->setText(BatV);
                this->ui->LE_BatC->setText(BatC);
                 if(FLAG_DORM_STATUS)
                 {
                     this->ui->LE_SysRTC->setText(dateTime);//只有mcu回复时间
                 }

                this->ui->LE_SDcard->setText(sdCardGB);
            }
            if(rx_str.contains("DORM"))
            {   //成功切换到睡眠，设置DORM状态灯为绿色
                setLED(this->ui->labDORM, 'g', LED_SIZE);//灰色
                qDebug()<<"receive DORM :"<<rx_str;
                setFLAG("FLAG_DORM");
                CommEnter=CLOSE_RX_SHOW;
            }
            else if(rx_str.contains("IDLE"))
            {
                setLED(this->ui->labIDLE, 'g', LED_SIZE);//绿色
                qDebug()<<"receive IDLE :"<<rx_str;
                setFLAG("FLAG_IDLE");
                CommEnter=CLOSE_RX_SHOW;
             }
            else if(rx_str.contains("AZCT,P,ACQU"))
            {
                setLED(this->ui->labACQU, 'g', LED_SIZE);//绿色
                qDebug()<<"receive ACQU :"<<rx_str;
                setFLAG("FLAG_ACQU");
                CommEnter=OPEN_RX_SHOW;//只有在进入ACQU状态时才打开接收显示，用来屏蔽状态切换时报文反馈
            }
            else
            {
                CommEnter=ENTER_STATE;
            }
        break;
        case ENTER_SET_LaunVol:
            if(rx_str.contains(command_tail))
            {
                setLED(this->ui->labIDLE, 'g', LED_SIZE);//绿色
                qDebug()<<"Set LaunVol successful !";
                setFLAG("FLAG_IDLE");
                CommEnter=CLOSE_RX_SHOW;
             }
            else
            {
                CommEnter=ENTER_SET_LaunVol;
            }
        break;
   }//end of switch
}


//使用自动连接机制时,按钮的clicked()信号，槽函数应命名为on_buttonName_clicked(),按照这些命名规则，Qt会自动将信号与槽函数进行连接。

//IDLE控制按钮
void MainWindow::on_pB_IDLE_clicked()
{
    if(serial_port->isOpen()){
        CommEnter=ENTER_IDLE;       
        initLED();//清空状态灯
        QByteArray tx_IDLE = IDLE_COMMAND.toUtf8();  // 将字符串转换为字节数组
        this->serial_port->write(tx_IDLE);//串口发送IDLE
        qDebug()<<"have enter IDLE";
    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
         qDebug()<<"please open serial first";
    }
}

//DORM控制按钮
void MainWindow::on_pB_DORM_clicked()
{
    if(serial_port->isOpen())
    {
        CommEnter=ENTER_DORM;
        initLED();//清空状态灯
        if(FLAG_DORM_STATUS)//已经处于睡眠状态时，再切换到睡眠没有反馈，直接DORM状态灯变绿
        {
             setLED(this->ui->labDORM, 'g', LED_SIZE);//灰色
             qDebug()<<"have already in DORM,nomore enter !";
        }
        else if(FLAG_ACQU_STATUS)//只允许从空闲状态进入睡眠
        {
             setLED(this->ui->labACQU, 'g', LED_SIZE);//灰色
             MessageBox::warning(this, "错误", "请先切换到空闲 ！");
        }
        else{
            QByteArray tx_DORM = DORM_COMMAND.toUtf8();  // 将字符串转换为字节数组
            this->serial_port->write(tx_DORM);//串口发送DORM
            qDebug()<<"have enter DORM";
        }
    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
         qDebug()<<"please open serial first";
    }

}

//ACQU控制按钮
void MainWindow::on_pB_ACQU_clicked()
{
    if(serial_port->isOpen())
    {
        CommEnter=ENTER_ACQU;
        initLED();//清空状态灯
        QByteArray tx_ACQU = ACQU_COMMAND.toUtf8();  // 将字符串转换为字节数组
        this->serial_port->write(tx_ACQU);//串口发送IDLE
        qDebug()<<"have enter ACQU";
    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
        qDebug()<<"please open serial first";
    }

}

//状态查询控制按钮
void MainWindow::on_pB_STATE_clicked()
{
    if(serial_port->isOpen())
    {
        CommEnter=ENTER_STATE;
        initLED();//清空状态灯
        QByteArray tx_STATE = STATE_COMMAND.toUtf8();  // 将字符串转换为字节数组
        this->serial_port->write(tx_STATE);//串口发送STATE
        qDebug()<<"have enter STATE";
    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
        qDebug()<<"please open serial first";
    }

}

//设置音量控制按钮
void MainWindow::on_pB_setLaunVol_clicked()
{
    if(serial_port->isOpen())
    {
        if(!FLAG_IDLE_STATUS)
        {
            MessageBox::warning(this, "错误", "请先切换到空闲 ！");
            return;
        }
        CommEnter=ENTER_SET_LaunVol;
        initLED();//清空状态灯
        QString strLaunVol="$ACZP,V,";
        QString vol= this->ui->LE_LaunVol->text();
        vol.remove(QRegularExpression("\\s+"));//结合正则表达式来移除字符串中的所有空格
        int volnum=vol.toInt();
        if(volnum<10||volnum>1000)
        {
            MessageBox::warning(this, "错误", "音量超出范围，请输入10~1000的音量！");
            return;
        }
        strLaunVol+=vol;
        strLaunVol+=command_tail;
        QByteArray tx_buf = strLaunVol.toUtf8();  // 将字符串转换为字节数组
        this->serial_port->write(tx_buf);//串口发送IDLE
        qDebug()<<"have enter Set LaunVol:"<<tx_buf;
    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
        qDebug()<<"please open serial first";
    }

}

//时间同步控制按钮
void MainWindow::on_pB_TimeSync_clicked()
{
    if(serial_port->isOpen())
    {
        if(!FLAG_IDLE_STATUS)//只允许在空闲状态进行时间同步
        {
            MessageBox::warning(this, "错误", "请先切换到空闲 ！");
            return;
        }
        else
        {
            CommEnter=ENTER_TIMESYNC;
            setLED(this->ui->labIDLE, 'b', LED_SIZE);//灰色
            // 获取当前的 Unix 时间戳（以秒为单位）
            qint64 unixTime = QDateTime::currentSecsSinceEpoch();
            // 将时间戳转换为 QByteArray 类型字符串
            QByteArray timeArray = QByteArray::number(unixTime);
            QString headStr="$ACZC,";
            QByteArray tx_TimeSync = headStr.toUtf8();  // 将字符串转换为字节数组
            tx_TimeSync+=timeArray;
            tx_TimeSync+=command_tail.toUtf8();
            this->serial_port->write(tx_TimeSync);//串口发送STATE
            qDebug()<<"have enter TIMESYNC:"<<tx_TimeSync;
            setLED(this->ui->labIDLE, 'g', LED_SIZE);//绿色
            //更新显示的系统时间
            QDateTime dateTime = QDateTime::fromSecsSinceEpoch(unixTime);
            QString formattedDateTime = dateTime.toString("yyyy/MM/dd");
            this->ui->LE_SysRTC->setText(formattedDateTime);
        }

    }
    else
    {
        MessageBox::warning(this, "错误", "请先打开串口！");
        qDebug()<<"please open serial first";
        return;
    }

}

/******************************************************************************
 * 函数名:processRxData
 *
 * 参数：data：串口读到的数据；outData:存放以'\n'为结尾完整的数据包，否则outData为空
 *
 ******************************************************************************/
void processRxData(const QByteArray& data, QByteArray& outData) {
    int index = data.indexOf('\n');//将返回第一个换行符的索引位置
    outData.clear();
    if (index != -1)
    {//收到完整数据包
        g_rxArr+= data;
        outData=g_rxArr;
    }
    else
    {
        g_rxArr += data;
    }
}

//实现自动将文本显示为指定的格式
void MainWindow::on_rB_sendMode_hex_toggled(bool checked)
{
    if(checked)
    {
        QString contentStr = this->ui->tE_sendcon->toPlainText();
        if (!contentStr.isEmpty())
        {
            this->ui->tE_sendcon->clear();
            qDebug() << "contentStr:" << contentStr;

            QByteArray byteArray = contentStr.toUtf8(); // 将QString转换为QByteArray
            QString contentHEX = byteArray.toHex().toUpper(); // 转换为十六进制，并转换为大写

            // 添加空格分隔
            QString spacedContentHEX;
            for (int i = 0; i < contentHEX.length(); i += 2)
            {
                spacedContentHEX += contentHEX.mid(i, 2) + " ";
            }

            qDebug() << "contentHEX:" << spacedContentHEX;
            this->ui->tE_sendcon->setPlainText(spacedContentHEX);
        }

    }

}

void MainWindow::on_rB_sendMode_text_toggled(bool checked)
{
    if(checked)
    {
        qDebug()<<"rB_sendMode_text is checked ";
        QString contentStr = this->ui->tE_sendcon->toPlainText();
        contentStr.remove(QRegularExpression("\\s+"));//结合正则表达式来移除字符串中的所有空格
        if(!contentStr.isEmpty())
        {
            this->ui->tE_sendcon->clear();
            qDebug()<<"contentStr:"<<contentStr;
            QByteArray byteArray = QByteArray::fromHex(contentStr.toUpper().toLatin1()); // 转换为QByteArray
            QString str = QString::fromUtf8(byteArray); // 转换为QString
            this->ui->tE_sendcon->setPlainText(str);
        }
    }
}
